package com.xiaoma.myaudience.biz.adapter;

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.SimpleAdapter;
import android.widget.TextView;


/**
 * An easy adapter to map static data to views defined in an XML file. You can
 * specify the data backing the list as an ArrayList of Maps. Each entry in the
 * ArrayList corresponds to one row in the list. The Maps contain the data for
 * each row. You also specify an XML file that defines the views used to display
 * the row, and a mapping from keys in the Map to specific views.
 * 
 * Binding data to views occurs in two phases. First, if a
 * {@link android.widget.SimpleAdapter.ViewBinder} is available,
 * {@link ViewBinder#setViewValue(android.view.View, Object, String)} is
 * invoked. If the returned value is true, binding has occurred. If the returned
 * value is false, the following views are then tried in order:
 * <ul>
 * <li>A view that implements Checkable (e.g. CheckBox). The expected bind value
 * is a boolean.
 * <li>TextView. The expected bind value is a string and
 * {@link #setViewText(TextView, String)} is invoked.
 * <li>ImageView. The expected bind value is a resource id or a string and
 * {@link #setViewImage(ImageView, int)} or
 * {@link #setViewImage(ImageView, String)} is invoked.
 * </ul>
 * If no appropriate binding can be found, an {@link IllegalStateException} is
 * thrown.
 */
public class CommentViewAdapter extends BaseAdapter implements Filterable {
   private int[] mTo;
   private String[] mFrom;
   private ViewBinder mViewBinder;
   private ViewBinderWithKey mViewBinderWithKey;
   private Context mContext;

   private int imgWidth = 0;
   private int imgHeight = 0;
   private String cut ;
   
   private List<? extends Map<String, ?>> mData;

   private int mResource;
   private int mDropDownResource;
   private LayoutInflater mInflater;
   private final WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();

   private SimpleFilter mFilter;
   private ArrayList<Map<String, ?>> mUnfilteredData;
   
   private String adapterType = "";
   private  SharedPreferences set_prefs;
    
   /**
    * Constructor
    * 
    * @param context
    *           The context where the View associated with this SimpleAdapter is
    *           running
    * @param data
    *           A List of Maps. Each entry in the List corresponds to one row in
    *           the list. The Maps contain the data for each row, and should
    *           include all the entries specified in "from"
    * @param resource
    *           Resource identifier of a view layout that defines the views for
    *           this list item. The layout file should include at least those
    *           named views defined in "to"
    * @param from
    *           A list of column names that will be added to the Map associated
    *           with each item.
    * @param to
    *           The views that should display column in the "from" parameter.
    *           These should all be TextViews. The first N views in this list
    *           are given the values of the first N columns in the from
    *           parameter.
    */
   public CommentViewAdapter(Context context,
         List<? extends Map<String, ?>> data, int resource, String[] from,
         int[] to) {
      mData = data;
      mResource = mDropDownResource = resource;
      mFrom = from;
      mTo = to;
      mInflater = (LayoutInflater) context
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      mContext = context;
      set_prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
   }
      
   public void setAdapterType(String type) {
	   this.adapterType = type;
   }
   
   public List<? extends Map<String, ?>>  getData() {
	   return mData;
   }
   
   /**
    * @see android.widget.Adapter#getCount()
    */
   public int getCount() {
      return mData.size();
   }

   /**
    * @see android.widget.Adapter#getItem(int)
    */
   public Object getItem(int position) {
      return mData.get(position);
   }

   /**
    * @see android.widget.Adapter#getItemId(int)
    */
   public long getItemId(int position) {
      return position;
   }

   /**
    * @see android.widget.Adapter#getView(int, View, ViewGroup)
    */
   public View getView(int position, View convertView, ViewGroup parent) {
      return createViewFromResource(position, convertView, parent, mResource);
   }

   private View createViewFromResource(int position, View convertView,
         ViewGroup parent, int resource) {
      View v;

      if (convertView == null) {
         v = mInflater.inflate(resource, parent, false);

         final int[] to = mTo;
         final int count = to.length;
         final View[] holder = new View[count];

         for (int i = 0; i < count; i++) {      	 
            holder[i] = v.findViewById(to[i]);
//            if(to[i] == R.id.title || to[i] == R.id.rank_comments_source){
//            	holder[i].setTag("title");
//            }
//            if(to[i] == R.id.category_title){
//            	holder[i].setTag("category_title");
//            }
//            if(to[i] == R.id.comment_count){
//            	holder[i].setTag("commentcount");
//            }
            	
         }

         mHolders.put(v, holder);

      } else {
         v = convertView;
      }


      bindView(position, v);

      return v;
   }

   /**
    * <p>
    * Sets the layout resource to create the drop down views.
    * </p>
    * 
    * @param resource
    *           the layout resource defining the drop down views
    * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
    */
   public void setDropDownViewResource(int resource) {
      this.mDropDownResource = resource;
   }

   @Override
   public View getDropDownView(int position, View convertView, ViewGroup parent) {
      return createViewFromResource(position, convertView, parent,
            mDropDownResource);
   }

   private void bindView(int position, View view) {
	  if(mData == null || mData.size() == 0) return;
      final Map dataSet = mData.get(position);
      if (dataSet == null) {
         return;
      }

      final ViewBinderWithKey binderWithKey = mViewBinderWithKey;
      final View[] holder = mHolders.get(view);
      final String[] from = mFrom;
      final int[] to = mTo;
      final int count = to.length;

      for (int i = 0; i < count; i++) {
         final View v = holder[i];
         if (v != null) {
            final Object data = dataSet.get(from[i]);
            
            binderWithKey.setViewValue(v, data, from[i]);
         }
            
      }
   }


   /**
    * Called by bindView() to set the rate for a RatingBar but only if there is
    * no existing ViewBinder or if the existing ViewBinder cannot handle binding
    * to an RatingBar.
    * 
    * @param v RatingBar which need to be set its rate.
    * @param value the rate value.
    */
   public void setRatingBar(RatingBar v, Object value) {
      float f = Float.parseFloat(value.toString());
      v.setRating(f);
   }  

   /**
    * Returns the {@link ViewBinder} used to bind data to views.
    * 
    * @return a ViewBinder or null if the binder does not exist
    * 
    * @see #setViewBinder(android.widget.SimpleAdapter.ViewBinder)
    */
   public ViewBinder getViewBinder() {
      return mViewBinder;
   }

   /**
    * Sets the binder used to bind data to views.
    * 
    * @param viewBinder
    *           the binder used to bind data to views, can be null to remove the
    *           existing binder
    * 
    * @see #getViewBinder()
    */
   public void setViewBinder(ViewBinder viewBinder) {
      mViewBinder = viewBinder;
   }

   /**
    * Called by bindView() to set the image for an ImageView but only if there
    * is no existing ViewBinder or if the existing ViewBinder cannot handle
    * binding to an ImageView.
    * 
    * This method is called instead of {@link #setViewImage(ImageView, String)}
    * if the supplied data is an int or Integer.
    * 
    * @param v
    *           ImageView to receive an image
    * @param value
    *           the value retrieved from the data set
    * 
    * @see #setViewImage(ImageView, String)
    */
   public void setViewImage(ImageView v, int value) {
      v.setImageResource(value);
   }

   /**
    * Called by bindView() to set the image for an ImageView but only if there
    * is no existing ViewBinder or if the existing ViewBinder cannot handle
    * binding to an ImageView.
    * 
    * By default, the value will be treated as an image resource. If the value
    * cannot be used as an image resource, the value is used as an image Uri.
    * 
    * This method is called instead of {@link #setViewImage(ImageView, int)} if
    * the supplied data is not an int or Integer.
    * 
    * @param v
    *           ImageView to receive an image
    * @param value
    *           the value retrieved from the data set
    * 
    * @see #setViewImage(ImageView, int)
    */
   public void setViewImage(ImageView v, String value) {

      Bitmap bm = null;

      try {
         //bm = ComTools.getImage(mContext, value);
         v.setImageBitmap(bm);
      } catch (Exception e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

   }

   /**
    * Called by bindView() to set the text for a TextView but only if there is
    * no existing ViewBinder or if the existing ViewBinder cannot handle binding
    * to an TextView.
    * 
    * @param v
    *           TextView to receive text
    * @param text
    *           the text to be set for the TextView
    */
   public void setViewText(TextView v, String text) {
      v.setText(text);
   }

   
   public Filter getFilter() {
      if (mFilter == null) {
         mFilter = new SimpleFilter();
      }
      return mFilter;
   }

   /**
    * This class can be used by external clients of SimpleAdapter to bind values
    * to views.
    * 
    * You should use this class to bind values to views that are not directly
    * supported by SimpleAdapter or to change the way binding occurs for views
    * supported by SimpleAdapter.
    * 
    * @see SimpleAdapter#setViewImage(ImageView, int)
    * @see SimpleAdapter#setViewImage(ImageView, String)
    * @see SimpleAdapter#setViewText(TextView, String)
    */
   public static interface ViewBinder {
      /**
       * Binds the specified data to the specified view.
       * 
       * When binding is handled by this ViewBinder, this method must return
       * true. If this method returns false, SimpleAdapter will attempts to
       * handle the binding on its own.
       * 
       * @param view
       *           the view to bind the data to
       * @param data
       *           the data to bind to the view
       * @param textRepresentation
       *           a safe String representation of the supplied data: it is
       *           either the result of data.toString() or an empty String but
       *           it is never null
       * 
       * @return true if the data was bound to the view, false otherwise
       */
      boolean setViewValue(View view, Object data, String textRepresentation);
   }
   
   public static interface ViewBinderWithKey {
	      boolean setViewValue(View view, Object data, String key);
   }
   
   public ViewBinderWithKey getViewBinderWithKey() {
	      return mViewBinderWithKey;
   }
   
   public void setViewBinderWithKey(ViewBinderWithKey viewBinderWithKey) {
	      mViewBinderWithKey = viewBinderWithKey;
   }

   /**
    * <p>
    * An array filters constrains the content of the array adapter with a
    * prefix. Each item that does not start with the supplied prefix is removed
    * from the list.
    * </p>
    */
   private class SimpleFilter extends Filter {

      @Override
      protected FilterResults performFiltering(CharSequence prefix) {
         FilterResults results = new FilterResults();

         if (mUnfilteredData == null) {
            mUnfilteredData = new ArrayList<Map<String, ?>>(mData);
         }

         if (prefix == null || prefix.length() == 0) {
            ArrayList<Map<String, ?>> list = mUnfilteredData;
            results.values = list;
            results.count = list.size();
         } else {
            String prefixString = prefix.toString().toLowerCase();

            ArrayList<Map<String, ?>> unfilteredValues = mUnfilteredData;
            int count = unfilteredValues.size();

            ArrayList<Map<String, ?>> newValues = new ArrayList<Map<String, ?>>(
                  count);

            for (int i = 0; i < count; i++) {
               Map<String, ?> h = unfilteredValues.get(i);
               if (h != null) {

                  int len = mTo.length;

                  for (int j = 0; j < len; j++) {
                     String str = (String) h.get(mFrom[j]);

                     String[] words = str.split(" ");
                     int wordCount = words.length;

                     for (int k = 0; k < wordCount; k++) {
                        String word = words[k];

                        if (word.toLowerCase().startsWith(prefixString)) {
                           newValues.add(h);
                           break;
                        }
                     }
                  }
               }
            }

            results.values = newValues;
            results.count = newValues.size();
         }

         return results;
      }

      @Override
      protected void publishResults(CharSequence constraint,
            FilterResults results) {
         // noinspection unchecked
         mData = (List<Map<String, ?>>) results.values;
         if (results.count > 0) {
            notifyDataSetChanged();
         } else {
            notifyDataSetInvalidated();
         }
      }
   }
}
